adblock: release 4.4.5-1
authorDirk Brenken <[email protected]>
Sun, 14 Dec 2025 06:06:52 +0000 (07:06 +0100)
committerDirk Brenken <[email protected]>
Sun, 14 Dec 2025 06:08:17 +0000 (07:08 +0100)
* hardened the uci config parsing
* added a fast, flexible & secure domain validator function, it eliminates > 99 % of garbage inputs
  - Please note: the "rule" in the feed file now only includes parameters for the domain validator,
    see readme for details. Please nuke a custom feed file from former versions - they are no longer
    compatible
* readme update
* LuCI: fixed a minor issue in the logread template
* LuCI: adapted the rule select options in the custom feed editor to use the new domain validator

Signed-off-by: Dirk Brenken <[email protected]>
net/adblock/Makefile
net/adblock/files/README.md
net/adblock/files/adblock.feeds
net/adblock/files/adblock.sh

index 489b62c5bce951602923a59fdd6849195ebf5ec8..d525dfbc207a892f7fc68e1a45225e37c4fddc94 100644 (file)
@@ -6,8 +6,8 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=adblock
-PKG_VERSION:=4.4.4
-PKG_RELEASE:=3
+PKG_VERSION:=4.4.5
+PKG_RELEASE:=1
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_MAINTAINER:=Dirk Brenken <[email protected]>
 
index d631b46f3b7d223dc3f9ca1f73aa24cf811dce6c..7cc43841ba2e5bce9387d5c694693c84df00b8c1 100644 (file)
@@ -63,11 +63,11 @@ A lot of people already use adblocker plugins within their desktop browsers, but
 * Full IPv4 and IPv6 support
 * Provides top level domain compression ('tld compression'), this feature removes thousands of needless host entries from the blocklist and lowers the memory footprint for the DNS backend
 * Provides a 'DNS Blocklist Shift', where the generated final DNS blocklist is moved to the backup directory and only a soft link to this file is set in memory. As long as your backup directory is located on an external drive, you should activate this option to save valuable RAM.
-* Source parsing by fast & flexible regex rulesets, all rules and feed information are placed in an external JSON file ('/etc/adblock/adblock.feeds')
+* Feed parsing by a very fast & secure domain validator, all domain rules and feed information are placed in an external JSON file ('/etc/adblock/adblock.feeds')
 * Overall duplicate removal in generated blocklist file 'adb_list.overall'
 * Additional local allowlist for manual overrides, located in '/etc/adblock/adblock.allowlist' (only exact matches).
 * Additional local blocklist for manual overrides, located in '/etc/adblock/adblock.blocklist'
-* Quality checks during blocklist update to ensure a reliable DNS backend service
+* Connection checks during blocklist update to ensure a reliable DNS backend service
 * Minimal status & error logging to syslog, enable debug logging to receive more output
 * Procd based init system support ('start', 'stop', 'restart', 'reload', 'enable', 'disable', 'running', 'status', 'suspend', 'resume', 'query', 'report')
 * Auto-Startup via procd network interface trigger or via classic time based startup
@@ -76,7 +76,7 @@ A lot of people already use adblocker plugins within their desktop browsers, but
 * Provides a detailed DNS Query Report with DNS related information about client requests, top (blocked) domains and more
 * Provides a powerful query function to quickly find blocked (sub-)domains, e.g. to allow certain domains
 * Includes an option to generate an additional, restrictive 'adb_list.jail' to block access to all domains except those listed in the allowlist file. You can use this restrictive blocklist manually e.g. for guest wifi or kidsafe configurations
-* Includes an option to force DNS requests to the local resolver
+* Contains an option to route DNS queries to the local resolver via corresponding firewall rules
 * Automatic blocklist backup & restore, these backups will be used in case of download errors and during startup
 * Send notification E-Mails, see example configuration below
 * Add new adblock feeds on your own with the 'Custom Feed Editor' in LuCI or via CLI, see example below
@@ -215,15 +215,16 @@ To get the status in the CLI, just call _/etc/init.d/adblock status_ or _/etc/in
 ~# /etc/init.d/adblock status
 ::: adblock runtime information
   + adblock_status  : enabled
-  + adblock_version : 4.4.2-r1
-  + blocked_domains : 914 804
-  + active_feeds    : 1hosts, adguard, adguard_tracking, certpl, doh_blocklist, hagezi, stevenblack, winspy
-  + dns_backend     : unbound (1.23.0-r1), /mnt/data/adblock/backup, 355.97 MB
+  + frontend_ver    : 4.4.5-r1
+  + backend_ver     : 4.4.5-r1
+  + blocked_domains : 575 335
+  + active_feeds    : 1hosts, adguard, adguard_tracking, bitcoin, certpl, doh_blocklist, hagezi, phishing_army, smarttv_tracking, stevenblack, winspy
+  + dns_backend     : unbound (1.24.2-r1), /mnt/data/adblock/backup, 232.20 MB
   + run_ifaces      : trigger: wan , report: br-lan
   + run_directories : base: /mnt/data/adblock, dns: /var/lib/unbound, backup: /mnt/data/adblock/backup, report: /mnt/data/adblock/report, jail: /tmp
-  + run_flags       : shift: â\9c\94, custom feed: â\9c\98, force: â\9c\94, flush: â\9c\98, tld: â\9c\94, search: â\9c\98, report: ✔, mail: ✔, jail: ✘
-  + last_run        : mode: restart, 2025-05-27T20:02:02+02:00, duration: 0m 26s, 1413.00 MB available
-  + system_info     : cores: 4, fetch: wget, Bananapi BPI-R3, mediatek/filogic, OpenWrt SNAPSHOT r29655-4dc10ec711 
+  + run_flags       : shift: â\9c\94, custom feed: â\9c\98, force: â\9c\94, flush: â\9c\98, tld: â\9c\94, search: â\9c\94, report: ✔, mail: ✔, jail: ✘
+  + last_run        : mode: reload, 2025-12-13T15:55:59+01:00, duration: 0m 46s, 1411.57 MB available
+  + system_info     : cores: 4, fetch: curl, Bananapi BPI-R3, mediatek/filogic, OpenWrt SNAPSHOT (r32305-52fa3728e5)
 ```
 
 <a id="best-practise-and-tweaks"></a>
@@ -311,16 +312,21 @@ A valid JSON source object contains the following information, e.g.:
 
 ```
        [...]
-       "adguard": {
-               "url": "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt",
-               "rule": "BEGIN{FS=\"[|^]\"}/^\\|\\|([[:alnum:]_-]{1,63}\\.)+[[:alpha:]]+\\^(\\$third-party)?$/{print tolower($3)}",
-               "size": "L",
-               "descr": "general"
+       "stevenblack": {
+               "url": "https://raw.githubusercontent.com/StevenBlack/hosts/master/",
+               "rule": "feed 0.0.0.0 2",
+               "size": "VAR",
+               "descr": "compilation"
        },
        [...]
 ```
 
-Add an unique feed name (no spaces, no special chars) and make the required changes: adapt at least the URL, the regex rule, the size and the description for a new feed.  
+Add an unique feed name (no spaces, no special chars) and make the required changes: adapt at least the URL, check/change the rule, the size and the description for a new feed.  
+The rule consist of max. 4 individual, space separated parameters:
+1. type: always 'feed' (required)
+2. prefix: an optional search term (a string literal, no regex) to identify valid domain list entries, e.g. '0.0.0.0'
+3. column: the domain column within the feed file, e.g. '2' (required)
+4. separator: an optional field separator, default is the character class '[[:space:]]'
 
 ## Support
 Please join the adblock discussion in this [forum thread](https://forum.openwrt.org/t/adblock-support-thread/507) or contact me by mail <[email protected]>
index 61eab61d6cb0a1e53f1b0d3a6bbc55951809c2cd..4fd52bace81541fdab58dca9b47271f4f83d30c8 100644 (file)
 {
        "1hosts": {
                "url": "https://raw.githubusercontent.com/badmojr/1Hosts/master/",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "VAR",
                "descr": "compilation"
        },
        "adguard": {
                "url": "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt",
-               "rule": "BEGIN{FS=\"[|^]\"}/^\\|\\|([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}\\^(\\$third-party)?$/{print tolower($3)}",
+               "rule": "feed 3 [|^]",
                "size": "L",
                "descr": "general"
        },
        "adguard_tracking": {
                "url": "https://raw.githubusercontent.com/AdguardTeam/cname-trackers/master/data/combined_disguised_trackers_justdomains.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "L",
                "descr": "tracking"
        },
        "android_tracking": {
                "url": "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/android-tracking.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "tracking"
        },
        "andryou": {
                "url": "https://gitlab.com/andryou/block/raw/master/kouhai-compressed-domains",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "L",
                "descr": "compilation"
        },
        "anti_ad": {
                "url": "https://raw.githubusercontent.com/privacy-protection-tools/anti-AD/master/anti-ad-domains.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "L",
                "descr": "compilation"
        },
        "anudeep": {
                "url": "https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt",
-               "rule": "/^(0\\.0\\.0\\.0 ([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($2)}",
+               "rule": "feed 0.0.0.0 2",
                "size": "M",
                "descr": "compilation"
        },
        "bitcoin": {
                "url": "https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/hosts.txt",
-               "rule": "/^(0\\.0\\.0\\.0 ([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($2)}",
+               "rule": "feed 0.0.0.0 2",
                "size": "S",
                "descr": "mining"
        },
        "certpl": {
                "url": "https://hole.cert.pl/domains/v2/domains.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "L",
                "descr": "phishing"
        },
        "cpbl": {
                "url": "https://raw.githubusercontent.com/bongochong/CombinedPrivacyBlockLists/master/NoFormatting/cpbl-ctld.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "XL",
                "descr": "compilation"
        },
        "disconnect": {
                "url": "https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "general"
        },
        "divested": {
                "url": "https://divested.dev/hosts-domains-wildcards",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "XXL",
                "descr": "compilation"
        },
        "doh_blocklist": {
                "url": "https://raw.githubusercontent.com/dibdot/DoH-IP-blocklists/master/doh-domains_overall.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "doh_server"
        },
        "firetv_tracking": {
                "url": "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/AmazonFireTV.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "tracking"
        },
        "games_tracking": {
                "url": "https://raw.githubusercontent.com/KodoPengin/GameIndustry-hosts-Template/master/Main-Template/hosts",
-               "rule": "/^(0\\.0\\.0\\.0 ([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($2)}",
+               "rule": "feed 0.0.0.0 2",
                "size": "S",
                "descr": "tracking"
        },
        "hblock": {
                "url": "https://hblock.molinero.dev/hosts_domains.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "XL",
                "descr": "compilation"
        },
        "hagezi": {
                "url": "https://raw.githubusercontent.com/hagezi/dns-blocklists/main/",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)*[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "VAR",
                "descr": "compilation"
        },
        "oisd_big": {
                "url": "https://big.oisd.nl/domainswild2",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "XXL",
                "descr": "general"
        },
        "oisd_nsfw": {
                "url": "https://nsfw.oisd.nl/domainswild2",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "XXL",
                "descr": "porn"
        },
        "oisd_nsfw_small": {
                "url": "https://nsfw-small.oisd.nl/domainswild2",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "M",
                "descr": "porn"
        },
        "oisd_small": {
                "url": "https://small.oisd.nl/domainswild2",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "L",
                "descr": "general"
        },
        "phishing_army": {
                "url": "https://phishing.army/download/phishing_army_blocklist_extended.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "phishing"
        },
        "smarttv_tracking": {
                "url": "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/SmartTV.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "tracking"
        },
        "spam404": {
                "url": "https://raw.githubusercontent.com/Dawsey21/Lists/master/main-blacklist.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "general"
        },
        "stevenblack": {
                "url": "https://raw.githubusercontent.com/StevenBlack/hosts/master/",
-               "rule": "/^(0\\.0\\.0\\.0 ([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($2)}",
+               "rule": "feed 0.0.0.0 2",
                "size": "VAR",
                "descr": "compilation"
        },
        "stopforumspam": {
                "url": "https://www.stopforumspam.com/downloads/toxic_domains_whole.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "spam"
        },
        "utcapitole": {
                "url": "https://dsi.ut-capitole.fr/blacklists/download/blacklists.tar.gz",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "VAR",
                "descr": "general"
        },
        "wally3k": {
                "url": "https://v.firebog.net/hosts/static/w3kbl.txt",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "compilation"
        },
        "whocares": {
                "url": "https://someonewhocares.org/hosts/hosts",
-               "rule": "/^(127\\.0\\.0\\.1 ([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($2)}",
+               "rule": "feed 127.0.0.1 2",
                "size": "M",
                "descr": "general"
        },
        "winspy": {
                "url": "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt",
-               "rule": "/^(0\\.0\\.0\\.0 ([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($2)}",
+               "rule": "feed 0.0.0.0 2",
                "size": "S",
                "descr": "win_telemetry"
        },
        "yoyo": {
                "url": "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=nohtml&showintro=0&mimetype=plaintext",
-               "rule": "/^(([[:alnum:]_-]{1,63}\\.)+[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower($1)}",
+               "rule": "feed 1",
                "size": "S",
                "descr": "general"
        }
index 89ef22b1bde23a201b6a7f026f60ac24b27a8bc9..445108d0964a473af87697ed487c9dae0ae97e10 100755 (executable)
@@ -89,7 +89,7 @@ f_load() {
        adb_fver="$(printf "%s" "${adb_packages}" | "${adb_jsoncmd}" -ql1 -e '@.packages["luci-app-adblock"]')"
        adb_sysver="$("${adb_ubuscmd}" -S call system board 2>/dev/null |
                "${adb_jsoncmd}" -ql1 -e '@.model' -e '@.release.target' -e '@.release.distribution' -e '@.release.version' -e '@.release.revision' |
-               "${adb_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s, %s %s %s %s",$1,$2,$3,$4,$5,$6}')"
+               "${adb_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s, %s %s (%s)",$1,$2,$3,$4,$5}')"
        f_conf
 
        if [ -z "${adb_cores}" ]; then
@@ -186,18 +186,95 @@ f_conf() {
                option_cb() {
                        local option="${1}" value="${2//\"/\\\"}"
 
-                       eval "${option}=\"${value}\""
+                       case "${option}" in
+                               *[!a-zA-Z0-9_]*)
+                                       ;;
+                               *)
+                                       eval "${option}=\"\${value}\""
+                                       ;;
+                       esac
                }
                list_cb() {
                        local append option="${1}" value="${2//\"/\\\"}"
 
-                       eval "append=\"\${${option}}\""
-                       eval "${option}=\"${append}${value} \""
+                       case "${option}" in
+                               *[!a-zA-Z0-9_]*)
+                                       ;;
+                               *)
+                                       eval "append=\"\${${option}}\""
+                                       eval "${option}=\"${append}${value} \""
+                                       ;;
+                       esac
                }
        }
        config_load adblock
 }
 
+# domain validation
+#
+f_chkdom() {
+       local type prefix column separator check
+
+       case "${1}" in
+               "feed"|"local")
+                       type="${1}"
+                       case "${2}" in
+                               [0-9])
+                                       prefix=""
+                                       column="${2}"
+                                       separator="${3:-[[:space:]]+}"
+                                       ;;
+                               *)
+                                       prefix="${2}"
+                                       column="${3}"
+                                       separator="${4:-[[:space:]]+}"
+                                       ;;
+                       esac
+                       ;;
+               "google")
+                       type="${1}"
+                       prefix=""
+                       column="${2}"
+                       separator="${3:-[[:space:]]+}"
+                       ;;
+       esac
+
+       check="${adb_lookupdomain//./\\.}"
+       "${adb_awkcmd}" -v type="${type}" -v pre="${prefix}" -v col="${column}" -v chk="${check}" -F "${separator}" '
+       {
+               domain = $col
+               # remove carriage returns and trim the input
+               gsub(/\r|^[[:space:]]+|[[:space:]]+$/, "", domain)
+               # add www. for google safe search
+               if (type=="google" && domain ~ /^\.+/) { sub(/^\.+/, "", domain); domain="www."domain }
+               # check optional search prefix
+               if (pre != "" && $1 != pre) next
+               # skip empty lines, comments and special domains
+               if (domain == "" || domain ~ ("^(#|localhost|loopback|" chk ")")) next
+               # no domain with trailing dot
+               if (substr(domain, length(domain), 1) == ".") next
+               # check total length (253 characters)
+               if (length(domain) > 253) next
+               n = split(domain, L, ".")
+               valid = 1
+               for (i = 1; i <= n; i++) {
+                       l = L[i]
+                       len = length(l)
+                       # label length 1–63
+                       if (len < 1 || len > 63) { valid = 0; break }
+                       # no leading/trailing hyphen
+                       if (l ~ /^-/ || l ~ /-$/) { valid = 0; break }
+                       # ASCII + hyphen
+                       if (l !~ /^[A-Za-z0-9-]+$/) { valid = 0; break }
+               }
+               # TLD must start with a letter or "xn--"
+               if (valid && L[n] !~ /^[A-Za-z]/ && L[n] !~ /^xn--/) valid = 0
+               if (valid) print tolower(domain)
+       }'
+
+       f_log "debug" "f_chkdom ::: name: ${src_name}, type: ${type}, prefix: ${prefix:-"-"}, column: ${column:-"-"}, separator: ${separator:-"-"}"
+}
+
 # status helper function
 #
 f_char() {
@@ -703,12 +780,11 @@ f_list() {
                        ;;
                "blocklist" | "allowlist")
                        src_name="${mode}"
-                       rset="/^(([[:alnum:]_-]{1,63}\\.)*[[:alpha:]][[:alnum:]-]{1,62}([[:space:]]|$))/{print tolower(\$1)}"
                        case "${src_name}" in
                                "blocklist")
                                        if [ -f "${adb_blocklist}" ]; then
                                                file_name="${adb_tmpfile}.${src_name}"
-                                               "${adb_awkcmd}" "${rset}" "${adb_blocklist}" >"${adb_tmpdir}/tmp.raw.${src_name}"
+                                               f_chkdom local 1 < "${adb_blocklist}" >"${adb_tmpdir}/tmp.raw.${src_name}"
                                                if [ -s "${adb_allowlist}" ]; then
                                                        "${adb_awkcmd}" 'NR==FNR{member[$1];next}!($1 in member)' "${adb_allowlist}" "${adb_tmpdir}/tmp.raw.${src_name}" >"${adb_tmpdir}/tmp.deduplicate.${src_name}"
                                                else
@@ -727,9 +803,9 @@ f_list() {
                                "allowlist")
                                        if [ -f "${adb_allowlist}" ] && [ "${adb_dnsallow}" != "0" ]; then
                                                file_name="${adb_tmpdir}/tmp.raw.${src_name}"
-                                               [ "${adb_lookupdomain}" != "localhost" ] && printf "%s\n" "${adb_lookupdomain}" | "${adb_awkcmd}" "${rset}" >"${file_name}"
-                                               "${adb_awkcmd}" "${rset}" "${adb_allowlist}" >>"${file_name}"
-                                               "${adb_awkcmd}" "${rset}" "${file_name}" >"${adb_tmpdir}/tmp.rem.${src_name}"
+                                               [ "${adb_lookupdomain}" != "localhost" ] && { printf "%s\n" "${adb_lookupdomain}" | f_chkdom local 1; } >"${file_name}"
+                                               f_chkdom local 1 < "${adb_allowlist}" >>"${file_name}"
+                                               f_chkdom local 1 < "${file_name}" >"${adb_tmpdir}/tmp.rem.${src_name}"
                                                eval "${adb_dnsallow}" "${file_name}" >"${adb_tmpdir}/tmp.add.${src_name}"
                                                out_rc="${?}"
                                                if [ "${adb_jail}" = "1" ] && [ "${adb_dnsstop}" != "0" ]; then
@@ -748,7 +824,6 @@ f_list() {
                        fi
                        case "${src_name}" in
                                "google")
-                                       rset="/^(\\.([[:alnum:]_-]{1,63}\\.)*[[:alnum:]-]{2,63}([[:space:]]|$))/{printf \"%s\n%s\n\",tolower(\"www\"\$1),tolower(substr(\$1,2,length(\$1)))}"
                                        safe_url="https://www.google.com/supported_domains"
                                        safe_cname="forcesafesearch.google.com"
                                        if [ -s "${adb_backupdir}/safesearch.${src_name}.gz" ]; then
@@ -759,7 +834,7 @@ f_list() {
                                                        "${adb_gzipcmd}" -cf "${adb_tmpdir}/tmp.load.safesearch.${src_name}" >"${adb_backupdir}/safesearch.${src_name}.gz"
                                                fi
                                        fi
-                                       [ -s "${adb_tmpdir}/tmp.load.safesearch.${src_name}" ] && safe_domains="$("${adb_awkcmd}" "${rset}" "${adb_tmpdir}/tmp.load.safesearch.${src_name}")"
+                                       [ -s "${adb_tmpdir}/tmp.load.safesearch.${src_name}" ] && safe_domains="$(f_chkdom google 1 < "${adb_tmpdir}/tmp.load.safesearch.${src_name}")"
                                        ;;
                                "bing")
                                        safe_cname="strict.bing.com"
@@ -810,9 +885,14 @@ f_list() {
                "prepare")
                        file_name="${src_tmpfile}"
                        if [ -s "${src_tmpload}" ]; then
-                               "${adb_awkcmd}" "${src_rset}" "${src_tmpload}" | "${adb_sedcmd}" "s/\r//g" |
-                                       { [ "${adb_tld}" = "1" ] && "${adb_awkcmd}" 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' || "${adb_catcmd}"; } |
-                                       "${adb_sortcmd}" ${adb_srtopts} -u >"${src_tmpfile}" 2>/dev/null
+                               if [ "${adb_tld}" = "1" ]; then
+                                       f_chkdom ${src_rset} < "${src_tmpload}" |
+                                               "${adb_awkcmd}" 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' |
+                                               "${adb_sortcmd}" ${adb_srtopts} -u >"${src_tmpfile}" 2>/dev/null
+                               else
+                                       f_chkdom ${src_rset} < "${src_tmpload}" |
+                                               "${adb_sortcmd}" ${adb_srtopts} -u >"${src_tmpfile}" 2>/dev/null
+                               fi
                                out_rc="${?}"
                                if [ "${out_rc}" = "0" ] && [ -s "${src_tmpfile}" ]; then
                                        f_list backup
@@ -1024,9 +1104,14 @@ f_query() {
                        for file in "${adb_backupdir}/adb_list".*.gz "${adb_blocklist}" "${adb_allowlist}"; do
                                suffix="${file##*.}"
                                if [ "${suffix}" = "gz" ]; then
-                                       "${adb_zcatcmd}" "${file}" 2>/dev/null |
-                                               { [ "${adb_tld}" = "1" ] && "${adb_awkcmd}" 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' || "${adb_catcmd}"; } |
-                                               "${adb_awkcmd}" -v f="${file##*/}" "BEGIN{rc=1};/^($search|.*\\.${search})$/{i++;if(i<=3){printf \"  + %-30s%s\n\",f,\$1;rc=0}else if(i==4){printf \"  + %-30s%s\n\",f,\"[...]\"}};END{exit rc}"
+                                       if [ "${adb_tld}" = "1" ]; then
+                                               "${adb_zcatcmd}" "${file}" 2>/dev/null |
+                                                       "${adb_awkcmd}" 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' |
+                                                       "${adb_awkcmd}" -v f="${file##*/}" "BEGIN{rc=1};/^($search|.*\\.${search})$/{i++;if(i<=3){printf \"  + %-30s%s\n\",f,\$1;rc=0}else if(i==4){printf \"  + %-30s%s\n\",f,\"[...]\"}};END{exit rc}"
+                                       else
+                                               "${adb_zcatcmd}" "${file}" 2>/dev/null |
+                                                       "${adb_awkcmd}" -v f="${file##*/}" "BEGIN{rc=1};/^($search|.*\\.${search})$/{i++;if(i<=3){printf \"  + %-30s%s\n\",f,\$1;rc=0}else if(i==4){printf \"  + %-30s%s\n\",f,\"[...]\"}};END{exit rc}"
+                                       fi
                                        rc="${?}"
                                else
                                        "${adb_awkcmd}" -v f="${file##*/}" "BEGIN{rc=1};/^($search|.*\\.${search})$/{i++;if(i<=3){printf \"  + %-30s%s\n\",f,\$1;rc=0}else if(i==4){printf \"  + %-30s%s\n\",f,\"[...]\"}};END{exit rc}" "${file}"
@@ -1233,7 +1318,8 @@ f_main() {
 
                # basic pre-checks
                #
-               if [ -z "${src_url}" ] || [ -z "${src_rset}" ]; then
+               if [ -z "${src_url}" ] || [ -z "${src_rset}" ] ||
+                       [ "${src_rset%% *}" != "feed" ]; then
                        f_list remove
                        continue
                fi